/*
 * Copyright (c) 2011-2014, fortiss GmbH.
 * Licensed under the Apache License, Version 2.0.
 *
 * Use, modification and distribution are subject to the terms specified
 * in the accompanying license file LICENSE.txt located at the root directory
 * of this software distribution. A copy is available at
 * http://chromosome.fortiss.org/.
 *
 * This file is part of CHROMOSOME.
 *
 * $Id: pnpControlUIFunction.c 7805 2014-03-13 09:54:35Z geisinger $
 */

/**
 * \file
 *         Source file for function pnpControlUI in component pnpControlUI.
 *
 * \author
 *         This file has been generated by the CHROMOSOME Modeling Tool (XMT)
 *         (fortiss GmbH).
 */

/******************************************************************************/
/***   Includes                                                             ***/
/******************************************************************************/
#include "configuratorExtension/adv/pnpControlUI/include/pnpControlUIFunction.h"

#include "configuratorExtension/adv/pnpControlUI/include/pnpControlUIFunctionWrapper.h"
#include "configuratorExtension/adv/pnpControlUI/include/pnpControlUIComponent.h"
#include "configuratorExtension/adv/pnpControlUI/include/pnpControlUIComponentWrapper.h"
#include "configuratorExtension/adv/pnpControlUI/include/pnpControlUIManifest.h"

#include "xme/core/logUtils.h"

// PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_C_INCLUDES) ENABLED START

#include "xme/core/plugAndPlay/include/plugAndPlayManager.h"
#include "xme/core/manifestRepository/include/manifestRepository.h"
#include "xme/core/manifestTypes.h"
#include "xme/core/node.h"
#include "xme/core/nodeManager/include/componentRepositoryBuilder.h"

#include "xme/hal/include/mem.h"
#include "xme/hal/include/safeString.h"
#include "xme/hal/include/sched.h"
#include "xme/hal/include/sync.h"
#include "xme/hal/include/time.h"

#include <ctype.h>
#include <limits.h>
#include <inttypes.h>

// PROTECTED REGION END

/******************************************************************************/
/***   Definitions                                                          ***/
/******************************************************************************/

// PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_C_DEFINITIONS) ENABLED START

// The following constants define the strings used in the different commands
// that the user can enter
#define ADD_STRING "add"
#define REMOVE_STRING "rem"
#define REMOVE2_STRING "remove"
#define LOGOUT_STRING "logout"
#define LIST_STRING "list"
#define LIST_NODES_STRING "nodes"
#define LIST_COMPONENTS_STRING "components"
#define LIST_COMPONENTS_VERBOSE_STRING "verbose"
#define LIST_TYPES_STRING "types"
#define BUILD_STRING "build"
#define SET_QUEUE_SIZE_STRING "setqs"
#define SET_EXECUTION_PERIOD_STRING "setep"
#define SET_INITIALIZATION_STRING_STRING "setis"
#define COMMIT_STRING "commit"
#define HELP_STRING "help"

#define CMD_BUFFER_SIZE 20 ///< Size of buffer for commands
#define CMD_STRLEN_STRING "19" ///< CMD_BUFFER_SIZE - 1 as string

/**
 * \brief Denotes type of command.
 */
typedef enum
{
    ADD, ///< Command for adding a new component. Uses addComponentCmdData_t as command data.
    REMOVE, ///< Command for removing a component. Uses removeComponentCmdData_t as command data.
    LOGOUT ///< Command for triggering logout of a node. Uses logoutCmdData_t as command data.
} commandType_t;

/**
 * \brief Command-specific data for add command.
 */
typedef struct
{
    xme_core_nodeMgr_compRep_componentHandle_t componentHandle; ///< Handle of component which should be plugged-in.
} addComponentCmdData_t;

/**
 * \brief Command-specific data for remove command.
 */
typedef struct
{
    xme_core_node_nodeId_t nodeID; ///< Node ID of node from which to remove a component.
    xme_core_component_t componentID; //< Component ID of component that should be removed.
} removeComponentCmdData_t;

/**
 * \brief Command-specific data for logout command.
 */
typedef struct
{
    xme_core_node_nodeId_t nodeID; ///< Node ID of node that should be logged out.
} logoutCmdData_t;

/**
 * \brief Union of all command-specific data types.
 */
typedef union
{
    addComponentCmdData_t addComponent;
    removeComponentCmdData_t removeComponent;
    logoutCmdData_t logout;
} commandData_t;

/**
 * \brief Data structure for storing commands, in command queue.
 */
typedef struct
{
    commandType_t commandType; ///< Denotes type of command, which in turn determines the commandData type.
    commandData_t commandData; ///< Command-specific data.
}
command_t;

// PROTECTED REGION END

/******************************************************************************/
/***   Variables                                                            ***/
/******************************************************************************/

// PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_C_VARIABLES) ENABLED START

/**
 * \brief Queue for storing commands.
 *        Will be filled in user input task and processed in the step function.
 */
static xme_hal_singlyLinkedList_t(CMD_BUFFER_SIZE) commandQueue;

/**
 * \brief Task handle for user input task. This task is responsible for
 *        receiving user input and filling the command queue.
 */
static xme_hal_sched_taskHandle_t userInputTaskHandle;

/**
 * \brief Mutex controlling access to commandQueue.
 */
static xme_hal_sync_criticalSectionHandle_t commandQueueMutex;

static xme_core_nodeMgr_compRep_componentBuilder_t* builder = NULL;

// PROTECTED REGION END

/******************************************************************************/
/***   Prototypes                                                           ***/
/******************************************************************************/

// PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_C_PROTOTYPES) ENABLED START

/**
 * \brief Callback function for separate thread that collects user input and
 *        fills command queue.
 */
void
userInputTask(void* userData);

/**
 * \brief Converts all characters in given string to lower case.
 *
 * \details Processing stops after null terminator is reached or maxLen
 *          characters are processed.
 *
 * \param[in] in Input string. Characters are read from here.
 * \param[out] out Output string. May be the same as in. Lower case characters
 *             are written to there.
 * \param[in] maxLen Maximum length of string.
 */
void
tolowerString(const char* const in, char* const out, uint32_t maxLen);

// PROTECTED REGION END

/******************************************************************************/
/***   Implementation                                                       ***/
/******************************************************************************/
xme_status_t
configuratorExtension_adv_pnpControlUI_pnpControlUIFunction_init
(
    configuratorExtension_adv_pnpControlUI_pnpControlUIComponent_config_t* const componentConfig
)
{
    // PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_INITIALIZE_C) ENABLED START
    
    XME_UNUSED_PARAMETER(componentConfig);

    commandQueueMutex = xme_hal_sync_createCriticalSection();

    XME_HAL_SINGLYLINKEDLIST_INIT(commandQueue);

    userInputTaskHandle = xme_hal_sched_addTask(0, xme_hal_time_timeIntervalFromSeconds(1u), 0, userInputTask, NULL);
    
    return XME_STATUS_SUCCESS;
    
    // PROTECTED REGION END
}

void
configuratorExtension_adv_pnpControlUI_pnpControlUIFunction_step
(
    configuratorExtension_adv_pnpControlUI_pnpControlUIComponent_config_t* const componentConfig
)
{
    
    {
        // PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_STEP_C) ENABLED START
        
        command_t* command = NULL;
        xme_status_t status;

        XME_UNUSED_PARAMETER(componentConfig);

        xme_hal_sync_enterCriticalSection(commandQueueMutex);
        {
            if (xme_hal_singlyLinkedList_getItemCount(&commandQueue) > 0)
            {
                command = (command_t*) xme_hal_singlyLinkedList_itemFromIndex(&commandQueue, (xme_hal_linkedList_index_t) 0);
                (void) xme_hal_singlyLinkedList_removeItem(&commandQueue, (void*) command, false);
            }
        }
        xme_hal_sync_leaveCriticalSection(commandQueueMutex);

        if (NULL != command)
        {
            switch (command->commandType)
            {
                case ADD:
                    {
                        status = xme_core_pnp_pnpManager_plugInNewComponent(command->commandData.addComponent.componentHandle);

                        if (XME_STATUS_SUCCESS != status) { XME_LOG(XME_LOG_ERROR, "Command could not be executed.\n"); }
                    }
                    break;
                case REMOVE:
                    {
                        status = xme_core_pnp_pnpManager_unannounceComponentOnNode
                        (
                            command->commandData.removeComponent.nodeID,
                            command->commandData.removeComponent.componentID
                        );

                        if (XME_STATUS_SUCCESS != status) { XME_LOG(XME_LOG_ERROR, "Command could not be executed.\n"); }
                    }
                    break;
                case LOGOUT:
                    {
                        status = xme_core_pnp_pnpManager_unannounceNode
                        (
                            command->commandData.logout.nodeID
                        );

                        if (XME_STATUS_SUCCESS != status) { XME_LOG(XME_LOG_ERROR, "Command could not be executed.\n"); }
                    }
                    break;
                default:
                    XME_LOG(XME_LOG_ERROR, "Error in command structure. Unknown command type: %d\n", command->commandType);
            }

            // Always free command
            xme_hal_mem_free(command);
        }
        
        // PROTECTED REGION END
    }
    
    {
        // PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_STEP_2_C) ENABLED START
        
        // Nothing to do here
        
        // PROTECTED REGION END
    }
}

void
configuratorExtension_adv_pnpControlUI_pnpControlUIFunction_fini
(
    configuratorExtension_adv_pnpControlUI_pnpControlUIComponent_config_t* const componentConfig
)
{
    // PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_TERMINATE_C) ENABLED START
    
    // TODO: Actually we need to cancel the thread (not supported by xme_hal_sched), as it has a blocking call and might never return!
    xme_hal_sched_removeTask(userInputTaskHandle);

    XME_UNUSED_PARAMETER(componentConfig);

    {
        xme_hal_linkedList_index_t queueItemCount;
        xme_hal_linkedList_index_t i;

        queueItemCount = xme_hal_singlyLinkedList_getItemCount(&commandQueue);

        for (i = 0; i < queueItemCount; i++)
        {
            void* item = xme_hal_singlyLinkedList_itemFromIndex(&commandQueue, i);
            if (NULL != item) { xme_hal_mem_free(item); }
        }

        XME_HAL_SINGLYLINKEDLIST_FINI(commandQueue);
    }

    xme_hal_sync_destroyCriticalSection(commandQueueMutex);
    
    // PROTECTED REGION END
}

// PROTECTED REGION ID(CONFIGURATOREXTENSION_ADV_PNPCONTROLUI_PNPCONTROLUIFUNCTION_IMPLEMENTATION_C) ENABLED START

void
userInputTask(void* userData)
{
    char inputBuffer[100];
    char cmdBuffer[CMD_BUFFER_SIZE];
    command_t* command = (command_t*)xme_hal_mem_alloc(sizeof(command_t));

    XME_UNUSED_PARAMETER(userData);

    XME_LOG
    (
        XME_LOG_ALWAYS,
        "\nEnter command (to print help type \"help\" without quotes):\n>"
    );
    XME_CHECK
    (
        inputBuffer == fgets(inputBuffer, sizeof(inputBuffer), stdin),
        XME_CHECK_RVAL_VOID
    );

#ifdef _MSC_VER
    (void)sscanf_s(inputBuffer, "%" CMD_STRLEN_STRING "s", cmdBuffer, CMD_BUFFER_SIZE);
#else
    (void)sscanf(inputBuffer, "%" CMD_STRLEN_STRING "s", cmdBuffer);
#endif

    tolowerString(cmdBuffer, cmdBuffer, CMD_BUFFER_SIZE);

    // TODO:
    // - Allow nodeName instead of nodeID (add "subscriberNode" 4099)
    // - Allow componentTypeName instead of componentType (add 2 "subscriber")

    if (0 == strcmp(cmdBuffer, BUILD_STRING))
    {
        xme_core_node_nodeId_t nodeID;
        xme_core_componentType_t componentType;

#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, BUILD_STRING " %d %d", &nodeID, &componentType);
#else
        (void)sscanf(inputBuffer, BUILD_STRING " %d %d", (int*)&nodeID, (int*)&componentType);
#endif
        xme_core_nodeMgr_compRep_cancelBuild(builder);

        builder = xme_core_nodeMgr_compRep_createBuilder(nodeID, componentType);

        return;
    }
    else if (0 == strcmp(cmdBuffer, SET_QUEUE_SIZE_STRING))
    {
        uint32_t portTypeID;
        uint32_t queueSize;

#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, SET_QUEUE_SIZE_STRING " %" PRIu32 " %" PRIu32, &portTypeID, &queueSize);
#else
        (void)sscanf(inputBuffer, SET_QUEUE_SIZE_STRING " %" PRIu32 " %" PRIu32, &portTypeID, &queueSize);
#endif

        XME_CHECK_MSG(queueSize <= UCHAR_MAX, XME_CHECK_RVAL_VOID, XME_LOG_ERROR, "Maximum queue size is 255.\n");

        xme_core_nodeMgr_compRep_builderSetQueueSize(builder, portTypeID, (uint8_t)queueSize);

        return;
    }
    else if (0 == strcmp(cmdBuffer, SET_EXECUTION_PERIOD_STRING))
    {
        uint32_t functionTypeID;
        xme_hal_time_timeInterval_t execPeriod;

#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, SET_EXECUTION_PERIOD_STRING " %" PRIu32 " %" PRIu64, &functionTypeID, (uint64_t*)&execPeriod);
#else
        (void)sscanf(inputBuffer, SET_EXECUTION_PERIOD_STRING " %" PRIu32 " %" PRIu64, &functionTypeID, (uint64_t*)&execPeriod);
#endif
        xme_core_nodeMgr_compRep_builderSetExecutionPeriod(builder, functionTypeID, execPeriod);

        return;
    }
    else if (0 == strcmp(cmdBuffer, SET_INITIALIZATION_STRING_STRING))
    {
        char* initializationString;
        size_t len = xme_hal_safeString_strnlen(inputBuffer, sizeof(inputBuffer));
        if (inputBuffer[len-1] == '\n')
        {
            inputBuffer[len-1] = 0;
        }
        initializationString = &inputBuffer[strlen(SET_INITIALIZATION_STRING_STRING)+1];
        xme_core_nodeMgr_compRep_builderSetInitializationString(builder, initializationString);

        return;
    }
    else if (0 == strcmp(cmdBuffer, COMMIT_STRING))
    {
        xme_status_t status;
        xme_core_nodeMgr_compRep_componentHandle_t componentHandle;

        status = xme_core_nodeMgr_compRep_build(builder, &componentHandle);
        builder = NULL;
        XME_CHECK_MSG(XME_STATUS_SUCCESS == status, XME_CHECK_RVAL_VOID, XME_LOG_ERROR, "Command could not be executed.\n");

        command->commandType = ADD;
        command->commandData.addComponent.componentHandle = componentHandle;
    }
    else if (0 == strcmp(cmdBuffer, ADD_STRING))
    {
        xme_status_t status;
        xme_core_node_nodeId_t nodeID;
        xme_core_componentType_t componentType;
        xme_core_nodeMgr_compRep_componentBuilder_t* addBuilder = NULL;
        xme_core_nodeMgr_compRep_componentHandle_t componentHandle;

#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, ADD_STRING " %d %d", &nodeID, &componentType);
#else
        (void)sscanf(inputBuffer, ADD_STRING " %d %d", (int*)&nodeID, (int*)&componentType);
#endif

        addBuilder = xme_core_nodeMgr_compRep_createBuilder(nodeID, componentType);
        XME_CHECK(NULL != addBuilder, XME_CHECK_RVAL_VOID);
        status = xme_core_nodeMgr_compRep_build(addBuilder, &componentHandle);
        XME_CHECK_MSG(XME_STATUS_SUCCESS == status, XME_CHECK_RVAL_VOID, XME_LOG_ERROR, "Command could not be executed.\n");

        command->commandType = ADD;
        command->commandData.addComponent.componentHandle = componentHandle;
    }
    else if (0 == strcmp(cmdBuffer, REMOVE_STRING))
    {
        command->commandType = REMOVE;

#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, REMOVE_STRING " %d %d", (int*)&command->commandData.removeComponent.nodeID, &command->commandData.removeComponent.componentID);
#else
        (void)sscanf(inputBuffer, REMOVE_STRING " %d %d", (int*)&command->commandData.removeComponent.nodeID, &command->commandData.removeComponent.componentID);
#endif
    }
    else if (0 == strcmp(cmdBuffer, REMOVE2_STRING)) // equivalent alternative for REMOVE_STRING
    {
        command->commandType = REMOVE;
#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, REMOVE2_STRING " %d %d", (int*)&command->commandData.removeComponent.nodeID, &command->commandData.removeComponent.componentID);
#else
        (void)sscanf(inputBuffer, REMOVE2_STRING " %d %d", (int*)&command->commandData.removeComponent.nodeID, &command->commandData.removeComponent.componentID);
#endif
    }
    else if (0 == strcmp(cmdBuffer, LOGOUT_STRING))
    {
        command->commandType = LOGOUT;
#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, LOGOUT_STRING " %d", (int*)&command->commandData.logout.nodeID);
#else
        (void)sscanf(inputBuffer, LOGOUT_STRING " %d", (int*)&command->commandData.logout.nodeID);
#endif
    }
    else if (0 == strcmp(cmdBuffer, LIST_STRING))
    {
        // TODO: Upper case LIST will not work here. More robust parsing needed.
#ifdef _MSC_VER
        (void)sscanf_s(inputBuffer, LIST_STRING " %" CMD_STRLEN_STRING "s", cmdBuffer, CMD_BUFFER_SIZE);
#else
        (void)sscanf(inputBuffer, LIST_STRING " %" CMD_STRLEN_STRING "s", cmdBuffer);
#endif

        tolowerString(cmdBuffer, cmdBuffer, CMD_BUFFER_SIZE);

        if (0 == strcmp(cmdBuffer, LIST_TYPES_STRING))
        {
            xme_core_manifestRepository_iterator_t iter;
            xme_core_componentManifest_t* compManifest;

            iter = xme_core_manifestRepository_initIterator();

            XME_LOG(XME_LOG_ALWAYS, "\nContent of manifest repository of this node:\n");
            XME_LOG(XME_LOG_ALWAYS, "             component type name | component type ID\n");
            XME_LOG(XME_LOG_ALWAYS, "---------------------------------|------------------\n");

            while (xme_core_manifestRepository_hasNext(iter))
            {
                compManifest = xme_core_manifestRepository_next(&iter);
                
                XME_LOG(XME_LOG_NOTE, "%32s | %5d\n", compManifest->name, compManifest->componentType);
            }

            xme_core_manifestRepository_finiIterator(iter);

            return;
        }
        else if (0 == strcmp(cmdBuffer, LIST_NODES_STRING))
        {
            // Print list of all nodes in the system

            char nodeNameBuffer[20];

            xme_core_directory_nodeRegistryController_nodeIDIterator_t nodeIDIterator;
                
            XME_LOG(XME_LOG_ALWAYS, "\nThe following nodes are registered in the system:\n");
            XME_LOG(XME_LOG_ALWAYS, "           node name | node ID\n");
            XME_LOG(XME_LOG_ALWAYS, "---------------------|--------\n");
        
            xme_core_directory_nodeRegistryController_initNodeIDIterator(&nodeIDIterator);
            while (xme_core_directory_nodeRegistryController_hasNextNodeID(&nodeIDIterator))
            {
                xme_core_node_nodeId_t nodeID;

                nodeID = xme_core_directory_nodeRegistryController_nextNodeID(&nodeIDIterator);

                xme_core_directory_nodeRegistryController_getNodeName(nodeID, nodeNameBuffer, sizeof(nodeNameBuffer));

                XME_LOG(XME_LOG_NOTE, "%20s | %2d\n", nodeNameBuffer, nodeID);
            }
            xme_core_directory_nodeRegistryController_finiNodeIDIterator(&nodeIDIterator);

            return;
        }
        else if (0 == strcmp(cmdBuffer, LIST_COMPONENTS_STRING))
        {
            // Print list of all components in the system

            bool verbose = false;
            char nodeNameBuffer[20];
            char portBuffer[6];
            char functionBuffer[30];

#ifdef _MSC_VER
            (void)sscanf_s(inputBuffer, LIST_STRING " " LIST_COMPONENTS_STRING " %" CMD_STRLEN_STRING "s", cmdBuffer, CMD_BUFFER_SIZE);
#else
            (void)sscanf(inputBuffer, LIST_STRING " " LIST_COMPONENTS_STRING " %" CMD_STRLEN_STRING "s", cmdBuffer);
#endif
            if (0 == strcmp(cmdBuffer, LIST_COMPONENTS_VERBOSE_STRING))
            {
                verbose = true;
            }

            XME_LOG(XME_LOG_ALWAYS, "\nThe following components are registered in the system:\n");
            if (verbose)
            {
                XME_LOG(XME_LOG_ALWAYS, "                      | comp. |                           | port: | function:\n");
                XME_LOG(XME_LOG_ALWAYS, "       node name (ID) | ID    |      comp. type name (ID) | queue | exec.period\n");
                XME_LOG(XME_LOG_ALWAYS, "----------------------|-------|---------------------------|-------|------------\n");
            }
            else
            {
                XME_LOG(XME_LOG_ALWAYS, "                      | comp. |\n");
                XME_LOG(XME_LOG_ALWAYS, "       node name (ID) | ID    |      comp. type name (ID)\n");
                XME_LOG(XME_LOG_ALWAYS, "----------------------|-------|--------------------------\n");
            }

            xme_core_nodeMgr_compRep_componentIteratorInit();
            while (xme_core_nodeMgr_compRep_componentIteratorHasNext())
            {
                xme_core_node_nodeId_t nodeID;
                xme_core_component_t componentID;
                xme_core_componentType_t componentType;
                xme_core_componentManifest_t manifest;
                xme_core_nodeMgr_compRep_componentHandle_t componentHandle;
                xme_core_nodeMgr_compRep_portHandle_t portHandle;
                xme_core_nodeMgr_compRep_functionHandle_t functionHandle;
                uint16_t i = 0u;

                componentHandle = xme_core_nodeMgr_compRep_componentIteratorNext();
                nodeID = xme_core_nodeMgr_compRep_getNodeID(componentHandle);
                componentID = xme_core_nodeMgr_compRep_getComponentID(componentHandle);
                componentType = xme_core_nodeMgr_compRep_getComponentType(componentHandle);
                xme_core_manifestRepository_findComponentManifest(componentType, &manifest);
                xme_core_directory_nodeRegistryController_getNodeName(nodeID, nodeNameBuffer, sizeof(nodeNameBuffer));

                if (verbose)
                {
                    XME_LOG(XME_LOG_NOTE, "%16s (%2d) | %5d | %17s (%5d) |       |\n", nodeNameBuffer, nodeID, componentID, manifest.name, componentType);
                }
                else
                {
                    XME_LOG(XME_LOG_NOTE, "%16s (%2d) | %5d | %17s (%5d)\n", nodeNameBuffer, nodeID, componentID, manifest.name, componentType);
                }

                if (verbose)
                {
                    i = 0u;
                    do
                    {
                        uint16_t queueSize;
                        xme_hal_time_timeInterval_t execPeriod;
                    
                        portHandle = xme_core_nodeMgr_compRep_getPort(componentHandle, i);
                        if (XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE != portHandle)
                        {
                            queueSize = xme_core_nodeMgr_compRep_getQueueSize(portHandle);
                            xme_hal_safeString_snprintf(portBuffer, sizeof(portBuffer), "%2d:%2" PRIu16, i, queueSize);
                        }
                        else
                        {
                            xme_hal_safeString_snprintf(portBuffer, sizeof(portBuffer), "       ");
                        }
                    
                        functionHandle = xme_core_nodeMgr_compRep_getFunction(componentHandle, i);
                        if (XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE != functionHandle)
                        {
                            execPeriod = xme_core_nodeMgr_compRep_getExecutionPeriod(portHandle);

                            if (0ull == execPeriod || 1000000ull < execPeriod)
                            {
                                execPeriod = execPeriod / 1000000ull;
                                xme_hal_safeString_snprintf(functionBuffer, sizeof(functionBuffer), "%2d:%2" PRIu64 "ms", i, execPeriod);
                            }
                            else 
                            {
                                xme_hal_safeString_snprintf(functionBuffer, sizeof(functionBuffer), "%2d:%2" PRIu64 "ns", i, execPeriod);
                            }
                        }
                        else
                        {
                            xme_hal_safeString_snprintf(functionBuffer, sizeof(functionBuffer), "       ");
                        }

                        XME_LOG(XME_LOG_NOTE, "                      |       |                           | %s | %s\n", portBuffer, functionBuffer);

                        i++;

                    } while (XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE != portHandle && XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE != functionHandle);
                }
            }
            xme_core_nodeMgr_compRep_componentIteratorFini();

            return;
        }
        else
        {
            XME_LOG(XME_LOG_ERROR, "Unknown command. Enter help to print available commands.");
            return;
        }
    }
    else if (0 == strcmp(cmdBuffer, HELP_STRING))
    {
        XME_LOG
        (
            XME_LOG_ALWAYS,
            "Enter one of the following commands:\n"
            "COMMAND [PARAMS...]            DESCRIPTION\n"
            "add <nodeID> <componentType>   Adds a new component of the given component type\n"
            "                               to the given node.\n"
            "rem <nodeID> <componentID>     Removes the given component instance from the\n"
            "                               given node.\n"
            "logout <nodeID>                Trigger logout of the given node.\n"
            "list nodes                     Prints list of all nodes.\n"
            "list components                Prints list of all components.\n"
            "list components verbose        Prints list of all components with verbose\n"
            "                               information.\n"
            "list types                     Prints list of all component types.\n"
            "\n"
            "Advanced options for building a component:\n"
            "build <nodeID> <componentType> Like \"add\", but the component is not immediately\n"
            "                               added. Use the following functions to further\n"
            "                               refine the component definition.\n"
            "setqs <portTypeID> <queueSize> Set queue size of the given port to the given\n"
            "                               value.\n"
            "setep <functTypeID> <timeInNs> Set execution period of the given function to\n"
            "                               the given time value in nanoseconds.\n"
            "setis <initializationString>   Set the initialization string for the new\n"
            "commit                         component. Finally add the constructed component.\n"
        );
        return;
    }
    else
    {
        XME_LOG(XME_LOG_ERROR, "Unknown command. Enter help to print available commands.");
        return;
    }

    xme_hal_sync_enterCriticalSection(commandQueueMutex);

    xme_hal_singlyLinkedList_addItem(&commandQueue, command);

    xme_hal_sync_leaveCriticalSection(commandQueueMutex);
}

void
tolowerString(const char* const in, char* const out, uint32_t maxLen)
{
    uint32_t i = 0;

    while (in[i] && i < maxLen)
    {
        out[i] = tolower(in[i]);
        i++;
    }
}

// PROTECTED REGION END
